// ==UserScript==
// @name          KeyGenius
// @namespace     http://kg.yubico.com
// @description   Enables the use of a YubiKey to log in to any web site, by storing passwords on a secure server.
// @version 0.8.1
// @include       *
// ==/UserScript==

/**
 * KeyGenius
 * http://kg.yubico.com
 * Dain Nilsson
 * 2009-05-13
 *
 * Released under the GPL license
 * http://www.gnu.org/copyleft/gpl.html
 **/
document.keygenius_login = {};
(function() {
	/* CONFIGURABLE VARIABLES */
	var server = 'https://kg.yubico.com/';
	var default_len = 16;
	var interval = 500;

	var submit = false;
	var inputs = [];
	var clones = [];
	var i=0;
	var clone = false;
	function listener(e) {
		e = e || window.event;
		var input = e.currentTarget || e.srcElement;
		if(e.keyCode == 13) {
			if(e.preventDefault) e.preventDefault();
			else e.returnValue = false;
			if(parse_input(input)) submit_form(input.form);
			return false;
		}
	}
	function init() {
	inputs = document.getElementsByTagName('input');
	for(var j=inputs.length-1; j>=0; j--) {
		if(inputs[j].type == 'password' 
			&& inputs[j].className.indexOf('keygenius') == -1) {
			inputs[j].className += ' keygenius';
			if(inputs[j].id == '') {
				inputs[j].id = 'in_'+j;
			}
			if(inputs[j].offsetWidth) {
				clone = true;
				clones[i] = inputs[j].cloneNode(true);
				clones[i].removeAttribute('maxLength');
				clones[i].removeAttribute('name');
				clones[i].id = 'kg_'+clones[i].id;
				inputs[j].style.display = 'none';
				inputs[j].parentNode.insertBefore(clones[i], inputs[j]);
			} else {
				clones[i] = inputs[j];
				clone = false;
			}
			mark_input(clones[i]);
			add_listener(clones[i], 'keypress', listener);
			if(clone) add_listener(clones[i++], 'keyup', function(e) {
				e = e || window.event;
				var input = e.currentTarget || e.srcElement;
				document.getElementById(input.id.substr(3)).value = input.value;
			});
		}
	}
	setTimeout(init, interval);
	}
	init();
	var forms = document.getElementsByTagName('form');
	for(var j=forms.length-1; j>=0; j--) {
		add_listener(forms[j], 'submit', submit_form);
	}
	function restore_all() {
		i--;
		for(;i>=0;i--) {
			restore_orig(clones[i]);
		}
	}
	function parse_input(input) {
        var res = input.value.match('^([-=]|(?:\\+(?:\\+{2}|[1-9][0-9]?)?))?([cbdefghijklnrtuv]{44})$');
        if(res === null) return true;
        var prefix = res[1];
        var yubi = res[2];
        var url = server+'?token='+yubi+'&url='+encodeURIComponent(window.location);
        if(prefix == '=') {
            input.value = yubi;
            return false;
        } else if(prefix === null || prefix === undefined || prefix == '') {
            submit = true;
        } else if(prefix.charAt(0) == '+') {
            if(prefix == '+') {
                var pw = prompt('KeyGenius - Enter password to store.', '');
		if(pw === null) {
			input.value = '';
			return false;
		}
                url += '&store='+encodeURIComponent(pw);
            } else {
                var len = prefix.substr(1);
                if(len == '++') len = default_len;
                url += '&gen='+len;
            }
        }
        if(typeof GM_xmlhttpRequest != 'undefined' && typeof chromium != 'object') {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                onload: function(data) {
                    if(data.status==200) {
		    	write(input, data.responseText);
                    }
                    if(submit) submit_form(input.form);
                }
            });
        } else {
            var sec = Math.random();
            document.keygenius_login[sec] = function(pw) {
                if(pw !== null) input.value=pw;
		write(input, input.value);
                if(submit) submit_form(input.form);
            }
            var s = document.createElement('script');
            url += '&callback=document.keygenius_login['+sec+']';
            s.setAttribute('src',url);
            document.getElementsByTagName('body')[0].appendChild(s);
        }
        return false;
	}
	function write(input, val) {
		input.value = val;
		if(input.id.substr(0,3) == 'kg_') {
			document.getElementById(input.id.substr(3)).value = val;
		}
	}
	function add_listener(elm, e, cb) {
		if(elm.addEventListener) elm.addEventListener(e, cb,false);
		else if(elm.attachEvent) elm.attachEvent('on'+e, cb);
		else eval('elm.on'+e+'=callable;');
	}
	function restore_orig(input) {
		if(input.id.substr(0,3) != 'kg_') return;
		var o = document.getElementById(input.id.substr(3));
		input.parentNode.removeChild(input);
		if (o.style.removeProperty) o.style.removeProperty('display');
		else o.style.display = 'inline-block';
	}
	var submitting = false;
	function submit_form(form) {
		if(submitting) {
			return;
		}
		submitting = true;
		restore_all();
		if(form.type != 'submit') {
			if(document.createEvent) {
				var e = document.createEvent('HTMLEvents');
				e.initEvent('submit', true, true);
				form.dispatchEvent(e);
				form.submit();
			} else if(document.createEventObject) {
				var e = document.createEventObject();
				form.fireEvent('onsubmit', e);
				form.submit();
			}
		}
	}
	function mark_input(e) {
		var s = e.style;
		s.border = '1px solid #77af03';
		s.backgroundImage = 'url()';
		s.backgroundPosition = 'center left';
		s.backgroundRepeat = 'no-repeat';
	}
}());
